群晖为任意文件夹下的视频文件生成(拼接)缩略图 您所在的位置:网站首页 群晖 file 群晖为任意文件夹下的视频文件生成(拼接)缩略图

群晖为任意文件夹下的视频文件生成(拼接)缩略图

2023-12-29 16:39| 来源: 网络整理| 查看: 265

最近自己折腾了一台黑群晖,安装ffmpeg替换系统自带的(俗成半洗白)以后就可以为 photo station 和 Moments 管理的视频文件生成缩略图了,在两者的 Web 界面以及 file station 中都可以正确展示视频缩略图。

个人实在用不惯 Monents 在管理照片和视频时按时间创建文件夹来存储的方式,这样导致通过 file station 或挂载硬盘管理文件时非常得不方便。因此选用了和很多人一样的方式——使用 photo station 把照片同步到 Moments 所管理的目录(/hone/Drive/Moments/)下,前者只负责同步、后者方便查看照片(但是我这里的Moments 还并不能识别人脸、主题,按位置分类以及智能助手的相似照片归类能用,以后再折腾把)。

另外本人还有这样的需求:很多小视频资源,最好能打标签管理,查看时候最好有文件名和缩略图。放到 Moments 里的话不太方便,一来不想和自己拍的照片啥的混在一起展示,二来用 Moments 看的话没了直观的文件名显示和标签。找来找去还是群晖 Drive 中给文件打标签的功能最方便易用,所以就把这些视频文件放到 /hone/Drive/xxxx/ 了。

现在的问题只剩下如何给它们创建缩略图,让网页 file station 和手机端群晖 Drive 应用正确显示。

搞清楚缩略图从哪里读取。查看有缩略图的视频,例如 /photo/xxxx/test.mp4,缩略图是放在 /photo/xxxx/@eaDir/test.mp4/ 下的,其中SYNOPHOTO_THUMB_SM.jpg、SYNOPHOTO_THUMB_M.jpg、SYNOPHOTO_THUMB_XL.jpg分别是低、中、高质量的缩略图,缩略图都是等比例缩放的,观察了几个,猜测低、中质量的图分别是放把视频分辨率的短边缩放到240、320像素,高质量的是原始分辨率(不一定准确,个人简单观察和猜测)。这个文件夹下还有一个SYNOPHOTO_FILM_H264.mp4文件,是指向源视频文件的软链接(可能只有源视频是无需转码的mp4格式时才是软连接,需要NAS做离线转码的话会把转码后的视频放在这里,这也是个人简单观察和猜测,不一定准确),不过试了试没有它不影响,本着最简单的原则就只创建一个写脚本批量对视频文件创建“./@eaDir/文件名/”目录,生成缩略图并命名为“SYNOPHOTO_THUMB_M.jpg”放进去,创建指向源视频文件的“SYNOPHOTO_FILM_H264.mp4”软链接。简单的shell脚本如下(只需要群晖额外安装一下负责数学计算用的命令bc,我是先装了ipkg之后用ipkg安装的),相比于从网上找到的使用python等语言的实现来说,应该可以算更简约的。我还突发奇想,可以按一定时间间隔或帧间隔生成2x2、3x3这种截图拼图做封面,就能通过缩略图方便地知道小视频整体内容了。后来试了试,对与手机端 群晖Drive 应用,它显示缩略图是按一个横着的长方形展示,缩略图居中填充,多余的部分就看不到了,所以采用1x2或2x1拼接(本来展示就小,做2x2甚至3x3的太小了看起来很不方便)的方式,使截取的两张缩略图拼接完更接近正方形,就能比较好地展示了,shell脚本如下:#!/bin/bash # 定义缩略图的宽或高的最大值 # 如果视频是竖版(宽小于高)则按宽缩放为WIDTH等比例缩放,如果视频是横版(宽大于等于高)则将高缩放为HEIGHT, WIDTH=320 HEIGHT=320 # 遍历本目录下的视频文件 for file in ./*.{mp4,MP4,mov,MOV}; do #echo $file if [ -f "$file" ]; then filename=$(basename "$file") #echo "Filename="$filename fi # 如果不存在,放缩略图的文件夹,创建 if [ ! -d "./@eaDir/$filename" ]; then mkdir "./@eaDir/$filename" echo "mkdir: ./@eaDir/"$filename fi if [ ! -f "./@eaDir/$filename/SYNOPHOTO_THUMB_M.jpg" ]; then # 生成 M规格(每个截图的短边为320p) 的缩略图(等比例缩放) DURATION=$(ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 $file) echo "Duration: "$DURATION RESOLUTION=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0:s=x $file) w=$(echo $RESOLUTION | cut -d "x" -f 1) h=$(echo $RESOLUTION | cut -d "x" -f 2) #echo [$w -gt $h] #FR=$(ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of default=noprint_wrappers=1:nokey=1 $file) #TOTAL_FRAMES=$(echo "$FR*$DURATION" | bc | cut -d'.' -f1) #echo $TOTAL_FRAMES #FRAME_INTERVAL=$[$TOTAL_FRAMES/4] COUNT=2 # 因为是只截2张图,interval=视频总时长/2 向下取整,那么按 fps=1/interval 截取就行 INTERVAL=$(echo "$DURATION/$COUNT" | bc | cut -d'.' -f1) if [ $w -gt $h ]; then ffmpeg -i $file -vf "fps=1/$INTERVAL,scale='if(gt(iw,ih),min($WIDTH,iw),-1)':'if(gt(iw,ih),-1,min($HEIGHT,ih))',tile=1x2" ./@eaDir/$filename/SYNOPHOTO_THUMB_M.jpg 2>/dev/null else ffmpeg -i $file -vf "fps=1/$INTERVAL,scale='if(gt(iw,ih),min($WIDTH,iw),-1)':'if(gt(iw,ih),-1,min($HEIGHT,ih))',tile=2x1" ./@eaDir/$filename/SYNOPHOTO_THUMB_M.jpg 2>/dev/null fi echo "Gen thumb file: "./@eaDir/$filename/SYNOPHOTO_THUMB_M.jpg #ln -s ../../$filename ./@eaDir/$filename/SYNOPHOTO_FILM_H264.mp4 #touch ./@eaDir/$filename/SYNOVIDEO_VIDEO_SCREENSHOT.jpg fi #ffmpeg -i $file -vf "fps=1/$INTERVAL,tile=3x3" $OUTPUT_FILE #ffmpeg -i $file -filter_complex "[0:v]select='not(mod(n\,$FRAME_INTERVAL))',scale=320:-1,tile=2x2" $OUTPUT_FILE #ffmpeg -i "$file" -ss 00:00:01.000 -vframes 1 -vf "scale='if(gt(iw,ih),min($WIDTH,iw),-1)':'if(gt(iw,ih),-1,min($HEIGHT,ih))''" "${file%.*}.jpg" done

脚本里对关键的部分都做了注释,如果有不懂的可以留言交流哈,大家可以按需修改为视频生成各种规格的截图拼接图。

3. 其他。脚本里有部分注释的代码,是测试的时候用了另一种按帧间隔截图的方法,体感开销和fps=1/interval的截取方法差不多,没严格测试,自己也不太了解,欢迎大佬指教。按帧间隔截图的命令如下:

# ffprobe是从视频流信息中读的,不用读取整个视频文件,所以开销很低的 # 获取帧率 FR=$(ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of default=noprint_wrappers=1:nokey=1 $file) # 获取视频时长,带小数点的,秒为单位 DURATION=$(ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 $file) # 估算视频总帧数,向下取整 TOTAL_FRAMES=$(echo "$FR*$DURATION" | bc | cut -d'.' -f1) # 要截图的数量,例如想做 3x4 拼接的截图(tile=3x4,3列4行) COUNT=12 # 计算截取的帧间隔 FRAME_INTERVAL=$[$TOTAL_FRAMES/$COUNT] # 截图并拼接,这里缩放scale参数用的320:-1表示宽缩放为320,高随之等比缩放,可自行发挥 ffmpeg -i $file -filter_complex "[0:v]select='not(mod(n\,$FRAME_INTERVAL))',scale=320:-1,tile=3x4" $OUTPUT_FILE



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有